//
//  DogAsynImage.swift
//  ImagePickerApp
//
//  Created by li on 2021/6/18.
//

import SwiftUI
import Combine


public struct DogAsynImage<Content: View, Placeholder: View>: View {
    
    /// 图片加载错误
    private enum DogAsynImageError: String, Error {
        case invalidUrl = "无效的url"
        case imageNull = "图片格式错误"
    }
    
    private enum LoadingState: Equatable {
        static func == (lhs: DogAsynImage<Content, Placeholder>.LoadingState, rhs: DogAsynImage<Content, Placeholder>.LoadingState) -> Bool {
            
            switch (lhs,rhs) {
            case (.none, .none):
                return true
            case (.loading, .loading):
                return true
            case ( .completion(_, _), .completion(_ , _)):
                return true
            default:
            return false
            }
            
        }
        
        /// 未开始
        case none
        /// 正在获取图片
        case loading
        /// 获取到图片
        case completion(Image?, String?)
    }

    var content: (Image) -> Content
    var placeholder: (String?) -> Placeholder
    @State private var loadingState: LoadingState
    @State private var url: String
    
    
    public init(url: String, @ViewBuilder content: @escaping (Image) -> Content, @ViewBuilder placeholder: @escaping (String?) -> Placeholder) {
        
        self.content = content
        self.placeholder = placeholder
        
        self.loadingState = .none
        self.url = url
    }

    
    public var body: some View {
        
        ZStack {
                    
            switch loadingState {
            case .completion(let image,let errMsg):
                if image == nil {
                    placeholder(errMsg)
                }else {
                    content(image!)
                }
            default:
                placeholder(nil)
            }
        }

        .onAppear {
            loadImage()
        }

    }
        
    
    private func loadImage() {
        
        if loadingState == LoadingState.loading {
            return
        }
        
        
        if loadImageFromCache() {
            
            return
        }
        
        loadingState = LoadingState.loading
        
        loadImageFromService()
    }
    
    /// 缓存获取图片
    private func loadImageFromCache() -> Bool {
        

        guard let cacheImage = DogTemporaryImageCache.shared[url] else {
            
            // 无缓存图
            return false
        }
        
        // 有缓存图
        withAnimation {
            loadingState = .completion(Image(uiImage: cacheImage), nil)
        }
        
        
        return true
    }
    
    /// 服务端获取图片
    /// - Parameter uuid: url更改生成一个新的唯一标志，防止异步加载顺序不一致造成图片显示不正确
    private func loadImageFromService() {
        
        guard let url = URL(string: self.url) else {
            
            self.loadingState = .completion(nil,DogAsynImageError.invalidUrl.rawValue)
            return
        }
        
        var request = URLRequest(url: url)
        request.timeoutInterval = 60

        URLSession.shared.dataTask(with: request) { data, reponse, error in

            guard let error = error else {

                guard let data = data, let uiimage = UIImage(data: data) else {

                    DispatchQueue.main.async {
                        self.loadingState = .completion(nil,DogAsynImageError.imageNull.rawValue)
                    }
                    return
                }
                
                let image = Image(uiImage: uiimage)
                
                if url.absoluteString == self.url {
                    DispatchQueue.main.async {
                        
                        withAnimation {
                            self.loadingState = .completion(image, nil)
                        }
                        
                        DogTemporaryImageCache.shared[self.url] = uiimage
                    }
                }else {
                    
                  // 啥也不用做
                }
                
                return
            }
            
            DispatchQueue.main.async {
                withAnimation {
                    self.loadingState = .completion(nil, error.localizedDescription)
                }
            }
        }
        .resume()
    }
}


struct DogAsynImage_Previews: PreviewProvider {
    
    static var previews: some View {
        

        let url = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimgsa.baidu.com%2Fexp%2Fw%3D500%2Fsign%3D8760c172b351f819f125034aeab54a76%2F09fa513d269759ee831f2792b1fb43166d22df18.jpg&refer=http%3A%2F%2Fimgsa.baidu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626591012&t=c169c3a9638894847a46140842b7308d"

        DogAsynImage(url: url) { image in
            
            image
            
        } placeholder: { errMsg in
            
            Color.red
        }
        .frame(width: 200, height: 200)
    }
}

